package com.family.relation.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ReadWrite;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.tdb.TDB;
import com.hp.hpl.jena.tdb.TDBFactory;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

public class TDBConnection {
	public static final String URI = "http://www.ia.cas.cn/baike_baidu/resource/";

	private static Dataset ds = null;

	private static String TDBPath = "TDB/lobal_relation";

	public static Dataset getDataset() {
		if (ds == null) {
			String rootPath = new String();
			try {
				rootPath = new File("").getCanonicalPath();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("得到根目录失败");
			}
			ds = TDBFactory.createDataset(rootPath + "/" + TDBPath);
			// ds = TDBFactory.createDataset("D:/Program Files/Apache Software
			// Foundation/Tomcat 7.0/TDB/neurodatacenter");
			// System.out.println("");
		}
		return ds;
	}

	public static void closeTDB() {
		if (ds != null) {
			ds.close();
			ds = null;
		}
	}

	public static void addModel(Model addModel) {
		Dataset dataset = TDBConnection.getDataset();
		dataset.begin(ReadWrite.WRITE);

		try {
			Model model = dataset.getDefaultModel();
			model.add(addModel);
			// Finally, commit the transaction.
			dataset.commit();
			// Or call .abort()
		} finally {
			dataset.end();
		}
	}

	public static void addNamedModel(String graphName, Model addModel) {
		Dataset dataset = TDBConnection.getDataset();
		dataset.begin(ReadWrite.WRITE);

		try {
			dataset.addNamedModel(graphName, addModel);

			// Finally, commit the transaction.
			dataset.commit();
			// Or call .abort()
		} finally {
			dataset.end();
		}
	}

	public static void addNamedModel(String graphName, String modelPath) {
		Dataset dataset = TDBConnection.getDataset();
		dataset.begin(ReadWrite.WRITE);
		Model tempModel = FileManager.get().loadModel(modelPath);
		try {
			dataset.addNamedModel(graphName, tempModel);
			// Finally, commit the transaction.
			dataset.commit();
			// Or call .abort()
		} finally {
			dataset.end();
		}
	}

	public static void deleteNamedModel(String graphName, Model addModel) {
		Dataset dataset = TDBConnection.getDataset();
		dataset.begin(ReadWrite.WRITE);

		try {
			dataset.removeNamedModel(graphName);
			// Finally, commit the transaction.
			dataset.commit();
			// Or call .abort()
		} finally {
			dataset.end();
		}
	}

	public static void main(String[] args) {
		TDBConnection temp = new TDBConnection();

	}

	public static void writeFile(String content, String fileName) {
		try {
			File f = new File(fileName);
			if (!f.exists()) {
				f.createNewFile();
			}
			OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "UTF-8");
			BufferedWriter writer = new BufferedWriter(write);
			// PrintWriter writer = new PrintWriter(new BufferedWriter(new
			// FileWriter(filePathAndName)));
			// PrintWriter writer = new PrintWriter(new
			// FileWriter(filePathAndName));
			writer.write(content);
			writer.newLine();
			writer.close();
		} catch (Exception e) {
			System.out.println(" write error ");
			e.printStackTrace();
		}
	}

	private static String getLabelorLocalName(Resource r) {
		if (r == null)
			return null;
		String labelOrLocal;
		Statement stmt = r.getProperty(RDFS.label);
		if (stmt == null) {
			labelOrLocal = r.getLocalName();
		} else {
			labelOrLocal = stmt.getObject().asLiteral().getString();
		}
		return labelOrLocal;
	}

	public void commonQuery(OutputStream output, String query) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);

		QueryExecution qExec = null;
		try {

			qExec = QueryExecutionFactory.create(query, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();

			ResultSetFormatter.out(output, rs);
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public void commonQueryCSV(OutputStream output, String query) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		// Model model = dataset.getDefaultModel();

		QueryExecution qExec = null;
		try {

			qExec = QueryExecutionFactory.create(query, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();

			ResultSetFormatter.outputAsCSV(output, rs);
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public void commonQueryJSON(OutputStream output, String query) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		// Model model = dataset.getDefaultModel();

		QueryExecution qExec = null;
		try {

			qExec = QueryExecutionFactory.create(query, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();

			ResultSetFormatter.outputAsJSON(output, rs);
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public void commonQueryXML(OutputStream output, String query) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		// Model model = dataset.getDefaultModel();

		QueryExecution qExec = null;
		try {

			qExec = QueryExecutionFactory.create(query, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();

			ResultSetFormatter.outputAsXML(output, rs);
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public static List<String> mapDirectly(String keywork) {
		List<String> resKBIds = new ArrayList<String>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);

		QueryExecution qExec = null;
		try {

			Model model = dataset.getDefaultModel();

			String prefix = " PREFIX owl:<http://www.w3.org/2002/07/owl#> "
					+ " PREFIX baidubaike:<http://www.ia.cas.cn/baike_baidu/resource/> "
					+ " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
					+ " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> "
					+ "PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> ";

			keywork = keywork.replace("\\", "\\\\");
			keywork = keywork.replace("\"", "\\\"");

			String queryStr = " select * {?s rdf:type \"" + keywork + "\"^^xsd:string}";
			// "select * {?s ?p ?o} limit 100";
			// System.out.println(queryStr);
			qExec = QueryExecutionFactory.create(prefix + queryStr, model);
			ResultSet rs = qExec.execSelect();

			while (rs.hasNext()) {
				String temp = rs.next().getResource("s").getLocalName();
				resKBIds.add(temp);
			}
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
		return resKBIds;
	}

	// Note: this is requried from the jsp, and adapt for only specific jsp
	// page.
	public static Map<String, String> srchResAndLabel(String sparql) {
		Map<String, String> resLabel = new HashMap<String, String>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		QueryExecution qExec = null;
		try {
			System.out.println("search resource and label as Map: " + sparql);
			qExec = QueryExecutionFactory.create(sparql, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();
			while (rs.hasNext()) {
				QuerySolution soln = rs.next();
				Resource temp = soln.getResource("s");
				String resString = temp.getURI();
				String tempLabel = soln.getLiteral("o").getString();
				System.out.println(resString + " -> " + tempLabel);
				resLabel.put(resString, tempLabel);
			}
			return resLabel;
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	// Note: this is requried from the jsp, and adapt for only specific jsp
	// page.
	public static Map<String, String> srchResAndLabel2(String sparql, String key) {
		Map<String, String> resLabel = new HashMap<String, String>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		QueryExecution qExec = null;
		try {
			System.out.println("search resource and label as Map: " + sparql);
			qExec = QueryExecutionFactory.create(sparql, dataset);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			ResultSet rs = qExec.execSelect();
			while (rs.hasNext()) {
				QuerySolution soln = rs.next();
				Resource temp = soln.getResource("s");
				String resString = temp.getURI();

				resLabel.put(resString, key);
			}
			return resLabel;
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public static Map<String, String> srchResByLabel(String keyword) {
		Map<String, String> resLabel = new HashMap<String, String>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);
		System.out.println("Search of: " + keyword + " :");
		try {
			// Model model = dataset.getDefaultModel();
			Model model = dataset.getNamedModel("http://dbpedia.org/");

			String prefix = " PREFIX owl:<http://www.w3.org/2002/07/owl#> "
					+ " PREFIX baidubaike:<http://www.ia.cas.cn/baike_baidu/resource/> "
					+ " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
					+ " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> "
					+ " PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> ";

			keyword = keyword.replace("\\", "\\\\");
			keyword = keyword.replace("\"", "\\\"");

			String queryStr = " select * {?s rdfs:label ?word. FILTER regex(?word,\"" + keyword
					+ "\"^^xsd:string,\"i\").}";
			// "select * {?s ?p ?o} limit 100";
			// System.out.println(queryStr);
			QueryExecution qExec = QueryExecutionFactory.create(prefix + queryStr, model);
			qExec.getContext().set(TDB.symUnionDefaultGraph, true);
			try {
				ResultSet rs = qExec.execSelect();
				while (rs.hasNext()) {
					QuerySolution soln = rs.next();
					Resource temp = soln.getResource("s");
					String resString = temp.getURI();
					String tempLabel = soln.getLiteral("word").getString();
					System.out.println("\t" + resString + " -> " + tempLabel);
					resLabel.put(resString, tempLabel);
				}
			} finally {
				if (qExec != null) {
					qExec.close();
				}
			}
			return resLabel;
		} finally {
			dataset.end();
		}
	}

	public static int addLabel(String keyword, String label) {
		int count = 0;
		List<Resource> list = new ArrayList<Resource>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.WRITE);

		QueryExecution qExec = null;
		try {

			Model model = dataset.getDefaultModel();

			String prefix = " PREFIX owl:<http://www.w3.org/2002/07/owl#> "
					+ " PREFIX baidubaike:<http://www.ia.cas.cn/baike_baidu/resource/> "
					+ " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
					+ " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> "
					+ "PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> ";

			keyword = keyword.replace("\\", "\\\\");
			keyword = keyword.replace("\"", "\\\"");

			String queryStr = " select * {?s baidubaike:标题 \"" + keyword + "\"^^xsd:string}";
			// "select * {?s ?p ?o} limit 100";

			qExec = QueryExecutionFactory.create(prefix + queryStr, model);
			ResultSet rs = qExec.execSelect();

			while (rs.hasNext()) {
				Resource r = rs.next().getResource("s");
				list.add(r);
				System.out.println(count + ": " + r.toString() + " -- " + keyword + " = " + label);
				count++;
			}
			for (int i = 0; i < list.size(); i++) {
				list.get(i).addLiteral(RDFS.label, label);
				// model.add(list.get(i),RDFS.label,label);
			}
			dataset.commit();
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
		return count;
	}

	public void addForeignerNameLabel() {
		// 1. get all resource and name, store into map
		// 2. iterate the map, and split the name, put the crrspnd label
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.WRITE);
		int count = 0;
		Map<Resource, String> map = new HashMap<Resource, String>();

		QueryExecution qExec = null;
		try {

			Model model = dataset.getDefaultModel();

			String prefix = " PREFIX owl:<http://www.w3.org/2002/07/owl#> "
					+ " PREFIX baidubaike:<http://www.ia.cas.cn/baike_baidu/resource/> "
					+ " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
					+ " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> "
					+ "PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> ";
			String queryStr = " select * {?s baidubaike:name ?o}";
			// "select * {?s ?p ?o} limit 100";

			qExec = QueryExecutionFactory.create(prefix + queryStr, model);
			ResultSet rs = qExec.execSelect();

			while (rs.hasNext()) {
				QuerySolution soln = rs.next();
				Resource r = soln.getResource("s");
				String name = soln.getLiteral("o").getString();
				map.put(r, name);
				System.out.println(count++ + ": " + r.toString() + " -- " + name);
			}
			for (Map.Entry<Resource, String> m : map.entrySet()) {
				count--;
				String name = m.getValue();
				String names[] = name.split("·");
				for (int i = 0; i < names.length; i++) {
					if (!names[i].equals("")) {
						m.getKey().addLiteral(RDFS.label, names[i]);
						System.out.println(count-- + ": " + m.getKey().toString() + " add label: " + names[i]);
					}
				}
			}
			dataset.commit();
		} finally {
			if (qExec != null)
				qExec.close();
			dataset.end();
		}
	}

	public void changeKBId(String kbOld, String kbNew) {
		// 1. get all predicate and object, store into map
		// 2. iterate the map, delete and add

		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.WRITE);
		int count = 0;
		List<Statement> oldStmts = new ArrayList<Statement>();

		try {

			Model model = dataset.getDefaultModel();
			Resource rOld = model.createResource(URI + kbOld);
			Resource rNew = model.createResource(URI + kbNew);

			StmtIterator itors = rOld.listProperties();
			while (itors.hasNext()) {
				Statement stmt = itors.next();
				oldStmts.add(stmt);
			}
			// add new statements
			for (int i = 0; i < oldStmts.size(); i++) {
				Statement stmt = oldStmts.get(i);
				model.add(rNew, stmt.getPredicate(), stmt.getObject());
			}
			// delete old statements
			model.remove(oldStmts);

			// while(rs.hasNext()){
			// QuerySolution soln = rs.next();
			// Property p = (Property) soln.get("p");
			// RDFNode o = soln.get("o");
			//
			// objects.add(o);
			// System.out.println(count++ + ": "+p.toString() + " -- "
			// +o.toString());
			// }
			// for(int i=0;i<predicates.size();i++){
			// Property pre = (Property) predicates.get(i);
			// RDFNode node = objects.get(i);
			// model.remove(rOld,pre,node);
			// }
			dataset.commit();
		} finally {
			dataset.end();
		}
	}

	public static List<String> getAllLabels() {
		List<String> labels = new ArrayList<String>();
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);

		QueryExecution qExec = null;
		try {

			Model model = dataset.getDefaultModel();

			String prefix = " PREFIX owl:<http://www.w3.org/2002/07/owl#> "
					+ " PREFIX baidubaike:<http://www.ia.cas.cn/baike_baidu/resource/> "
					+ " PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
					+ " PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> "
					+ "PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> ";

			String queryStr = " select distinct ?p {?s rdfs:label ?p}";
			qExec = QueryExecutionFactory.create(prefix + queryStr, model);
			try {
				ResultSet rs = qExec.execSelect();
				while (rs.hasNext()) {
					String label = rs.next().getLiteral("p").getString();
					labels.add(label);
					// System.out.println("label"+label);
				}
			} finally {
				if (qExec != null)
					qExec.close();
			}
			return labels;
		} finally {
			dataset.end();
		}
	}

	public static Resource getType(String KBId) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.READ);

		Resource rCate = null;
		try {
			Model model = dataset.getDefaultModel();
			Resource rSub = model.createResource(URI + KBId);
			NodeIterator iter = model.listObjectsOfProperty(rSub, RDF.type);
			if (iter.hasNext()) {
				rCate = iter.next().asResource();
				System.out.println(rCate.toString());
			}
			return rCate;
		} finally {
			dataset.end();
		}
	}

	public static void removeLabels(String kbId) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.WRITE);

		try {
			Model model = dataset.getDefaultModel();
			Resource r = model.createResource(URI + kbId);
			r.removeAll(RDFS.label);

			dataset.commit();
		} finally {
			dataset.end();
		}
	}

	public static void addLabel2Re(String kbId, String label) {
		Dataset dataset = getDataset();
		dataset.begin(ReadWrite.WRITE);

		try {
			Model model = dataset.getDefaultModel();
			Resource r = model.createResource(URI + kbId);
			r.addLiteral(RDFS.label, label);

			dataset.commit();
		} finally {
			dataset.end();
		}
	}

}
